#pragma once

#include <windows.h>
#include <string>

namespace std
{
#ifdef UNICODE
	typedef wstring tstring;
#else
	typedef string tstring;
#endif
}

namespace hooker
{
#pragma pack(push,1)
	struct Thunk
	{
		BYTE    m_jmp;          // op code of jmp instruction
		DWORD   m_relproc;      // relative jmp
	};
#pragma pack(pop)

	template<typename _THookedFunc>
	struct RestoreThunk
	{
		_THookedFunc	hookedFunc;
		_THookedFunc	originalFunc;
		char*			savedMachineCode;
	};

	template<typename _TRestoreThunk>
	void HookApi(_TRestoreThunk& restoreThunk)
	{	
		
		
		DWORD oldProtect;

		VirtualProtect(restoreThunk.originalFunc, sizeof(Thunk), PAGE_READWRITE, &oldProtect);

		restoreThunk.savedMachineCode = reinterpret_cast<char*>(
			VirtualAlloc(NULL, 
			sizeof(Thunk)*2, 
			MEM_COMMIT, 
			PAGE_EXECUTE_READWRITE));

		memcpy(restoreThunk.savedMachineCode, restoreThunk.originalFunc, sizeof(Thunk));

		((Thunk*)(restoreThunk.savedMachineCode+sizeof(Thunk)))->m_jmp = 0xE9;
		((Thunk*)(restoreThunk.savedMachineCode+sizeof(Thunk)))->m_relproc 
			= (DWORD)((char*)restoreThunk.originalFunc - restoreThunk.savedMachineCode) - sizeof(Thunk);

		Thunk thunk;
		thunk.m_jmp = 0xE9;
		thunk.m_relproc = (DWORD)((char*)restoreThunk.hookedFunc - (char*)restoreThunk.originalFunc) - sizeof(Thunk);

		WriteProcessMemory(
				GetCurrentProcess()
			,	restoreThunk.originalFunc
			,	&thunk
			,	sizeof(thunk)
			,	nullptr);

		VirtualProtect(restoreThunk.originalFunc, sizeof(Thunk), oldProtect, &oldProtect);	
	}


	template<typename _TRestoreThunk>
	void UnhookApi(_TRestoreThunk& restoreThunk)
	{
		DWORD oldProtect;

		VirtualProtect(restoreThunk.originalFunc, sizeof(Thunk), PAGE_READWRITE, &oldProtect);

		WriteProcessMemory(
			GetCurrentProcess()
			,	restoreThunk.originalFunc
			,	restoreThunk.savedMachineCode
			,	sizeof(restoreThunk.savedMachineCode)
			,	nullptr);

		VirtualProtect(restoreThunk.originalFunc, sizeof(Thunk), oldProtect, &oldProtect);
	}

}


